module MidLevelLanguageTokenizer where

data Token = Variable String Int -- name, value
        | CharacterVariable String Char -- name, value
        | Conditional CondType String Comparator Int -- conditional type, variable, comparator, comparation
        | Loop String Int Int   -- variable, initial value, end value
        | EndBlock
        | Operation OpType String Int -- operation, variable, value

data CondType = If | While
        deriving (Enum, Show, Read, Eq)
data Comparator = Equal | NotEqual | Bigger | BiggerEq | Lesser | LesserEq
        deriving (Enum, Show, Read, Eq)
data OpType = Increment | Decrement | Read | Write
        deriving (Enum, Show, Read, Eq)

-- | Tokenizes a bunch of Mid-level instructions
tokenize :: [String] -> [Token]
tokenize [] = []
tokenize (x:xs)
        -- Variables
        | var                   = vaT : tokenize xs
        -- Conditionals
        | cond && elem "==" w   = eqT : tokenize xs
        | cond && elem "!=" w   = neT : tokenize xs
        | cond && elem ">" w    = bgT : tokenize xs
        | cond && elem ">=" w   = beT : tokenize xs
        | cond && elem "<" w    = lsT : tokenize xs
        | cond && elem "<=" w   = leT : tokenize xs
        | elem "end" w          = endT : tokenize xs
        -- Loops
        | loop && length w == 2 = iForT : tokenize xs 
        | loop && length w >= 4 = forT : tokenize xs
        -- Variable Manipulation
        | inc                   = incT : tokenize xs
        | dec                   = decT : tokenize xs
        -- I/O
        | rea                   = charT : readT : tokenize xs
        | wri                   = writeT : tokenize xs
        -- TODO: complete with rest of the tokens
        | otherwise             = tokenize xs
        where   w = words x
                -- Conditions
                var = length w == 3 && elem "=" w
                cond = length w >= 4 && elem "if" w
                loop = elem "for" w
                inc = elem "++" w
                dec = elem "--" w
                rea = elem "read" w
                wri = elem "print" w
                -- Tokens (aka Productions)
                vaT = (Variable ((!!) w 0)                        -- Variable
                        (read ((!!) w 2) :: Int))
                eqT = (Conditional (read "If" :: CondType)        -- Equal
                        ((!!) w 1) (read "Equal" :: Comparator)
                        (read((!!) w 3) :: Int))                
                neT = (Conditional (read "If" :: CondType)        -- Not equal
                        ((!!) w 1) (read "NotEqual" :: Comparator)
                        (read((!!) w 3) :: Int))                
                bgT = (Conditional (read "If" :: CondType)        -- Bigger
                        ((!!) w 1) (read "Bigger" :: Comparator)
                        (read((!!) w 3) :: Int))
                beT = (Conditional (read "If" :: CondType)        -- Bigger or equal
                        ((!!) w 1) (read "BiggerEq" :: Comparator)
                        (read((!!) w 3) :: Int))
                lsT = (Conditional (read "If" :: CondType)        -- Lesser
                        ((!!) w 1) (read "Lesser" :: Comparator)
                        (read((!!) w 3) :: Int))
                leT = (Conditional (read "If" :: CondType)        -- Lesser or equal
                        ((!!) w 1) (read "LesserEq" :: Comparator)
                        (read((!!) w 3) :: Int))
                endT = (EndBlock)                                 -- Block ending
                iForT = (Loop "" 0 0)                             -- Empty (infinite) for
                forT = (Loop ((!!) w 2) (read ((!!) w 4) :: Int)  -- Usual for
                        (read ((!!) w 6) :: Int))
                incT = (Operation (read "Increment" :: OpType)    -- Increment operation
                        (w !! 0) 1) 
                decT = (Operation (read "Decrement" :: OpType)    -- Decrement operation
                        (w !! 0) 1) 
                readT = (Operation (read "Read" :: OpType)        -- Read operation
                        (w !! 1) 0)
                writeT = (Operation (read "Write" :: OpType)      -- Write operation
                        (w !! 1) 0) 
                charT = (CharacterVariable (w !! 1) '\0')         -- New Character
                        
                
-- | For debugging purposes, mostly. DON'T use this, it's not complete and it's bound
-- to disappear soon.
showToken :: Token -> String
showToken (Variable n v) = n ++ " = " ++ show v
showToken (Conditional ct v cm ci) = show ct ++ " " ++ v ++ " " ++ show cm ++ " " ++ show ci
showToken (Loop var ini end) = "for " ++ var ++ " = " ++ show ini ++ " : " ++ show end
showToken (EndBlock) = "end"
showToken _ = ""
